#include "affix.hpp"

#include "qbe/src/ecs/app.hpp"

#include "qbe/src/ecs/query.hpp"

#include "qbe/src/axis/axis.hpp"
#include "qbe/src/input/input.hpp"
#include "qbe/src/select/select.hpp"
#include "qbe/src/state/state.hpp"
#include "qbe/src/undoRedo/undoRedo.hpp"
#include "qbe/src/utils/utils.hpp"

#include "qbe/src/layout/layout.hpp"

#include "qlib/all.h"

#include "components.hpp"
#include "events.hpp"

#include "../copy/copy.hpp"
#include "../shear/shear.hpp"

#include "../move/move.hpp"

#include "../../draw/pin/pin.hpp"

#include <QMessageBox>

namespace qbe::affix {

void clear_tag(ecs::Query query) {
  auto& move_param = query.get_resource<Param>();

  auto& cell = query.get_resource<qlib::Cell::s_ptr>();
  auto& reg = cell->reg;

  if (move_param.clear) {
    move_param.clear = false;
  }
}

void clear_events(ecs::Query query) {
  query.get_resource<ecs::Event<Event>>().clear();
}

// 添加临时对象
void add_cache_obj(qlib::Cell::s_ptr cell, entt::registry& reg, ecs::EventWriter<Event> event_writer, layout::LayoutCmd& cmd, entt::entity entity,
                   bool first) {
  if (first) {
    Event event;
    event.cell = cell;
    event.reg = &reg;
    event.code = Code::Begin;
    event_writer.send(std::move(event));
  }

  reg.emplace_or_replace<AffixTag>(entity);
}

// 更新临时对象
void update_cache_obj(entt::registry& reg, ecs::EventWriter<Event> event_writer, layout::LayoutCmd& cmd, qlib::Vec2d translate_a,
                      qlib::Vec2d translate_b) {
  Event event;
  event.code = Code::Update;
  event.translate_a = translate_a;
  event.translate_b = translate_b;
  event_writer.send(std::move(event));
}

// 删除临时对象
void delete_cache_obj(entt::registry& reg, ecs::EventWriter<Event> event_writer, layout::LayoutCmd& cmd, ecs::Query query) {
  Event event;
  event.code = Code::End;
  event_writer.send(std::move(event));

  auto& models = query.get_resource<Param>();

  auto& copy_models = query.get_resource<copy::Param>();
  auto& shear_models = query.get_resource<shear::Param>();

  entt::registry* form_reg = nullptr;
  if (models.from_copy) {
    form_reg = copy_models.reg;
  } else {
    form_reg = shear_models.reg;
  }

  if (form_reg) {
    auto view = form_reg->view<AffixTag>();
    view.each([&form_reg](entt::entity e) { form_reg->remove<AffixTag>(e); });
  }

  if (!models.from_copy) {
    shear_models.clear(reg);
  }
}

// 退出移动模式时回调
void exit_callback(ecs::Query query, state::AllModeType mode) {
  // 获取移动参数
  auto& move_param = query.get_resource<Param>();

  // 判断移动模式是否在执行
  auto& layout_cmd = query.get_resource<layout::LayoutCmd>();
  auto event_writer = query.get_event_writer<Event>();

  // 获取reg
  auto& cell = query.get_resource<qlib::Cell::s_ptr>();
  auto& reg = cell->reg;

  // 原对象不变，仅移除标记
  auto view_old = reg.view<AffixTag>();
  view_old.each([&reg](entt::entity entity) { reg.remove<AffixTag>(entity); });

  // 删除临时对象
  delete_cache_obj(reg, event_writer, layout_cmd, query);

  move_param.reset();
}

void init(ecs::Commands commands, ecs::Query query) {
  Param param;
  commands.insert_resource(param);

  auto& state = query.get_resource<state::State>();
  state.addExitCall(state::EditingModeType::Affix, exit_callback);
}

// 退出模式
void exit(ecs::Query query) {
  // 获取移动参数
  auto& move_param = query.get_resource<Param>();

  auto& layout_cmd = query.get_resource<layout::LayoutCmd>();
  auto event_writer = query.get_event_writer<Event>();

  // 获取reg
  auto& cell = query.get_resource<qlib::Cell::s_ptr>();
  auto& reg = cell->reg;

  // 原对象不变，仅移除标记
  auto view_old = reg.view<AffixTag>();
  view_old.each([&reg](entt::entity entity) { reg.remove<AffixTag>(entity); });

  // 删除临时对象
  delete_cache_obj(reg, event_writer, layout_cmd, query);

  move_param.reset();

  // 退出模式
  auto& state = query.get_resource<state::State>();
  state.exit();
}

// 帧开始，模式转换
void stateTransformBegin(Param& param, state::State& state, input::HandleBundle* handle, ecs::Bus& bus) {
  assert(param.state == State::None);

  if (param.moveing_first) {
    param.state = State::Upatde;
  }

  if (handle->keyReleased(vsg::KEY_Escape)) {
    param.state = State::Cancel;
    return;
  }

  if (handle->mousePressed(vsg::BUTTON_MASK_1) && param.moveing) {
    param.state = State::Complete;
    param.moveing = false;
    return;
  }

  if (handle->mouse_move && param.moveing) {
    param.state = State::Upatde;
    return;
  }
}

// 帧尾-退出模式
void stateTransformEnd(State& state) {
  // 操作模式执行完就回退
  if (state == State::Upatde || state == State::Complete || state == State::Cancel) {
    state = State::None;
  }
}

// 移动逻辑
void update(ecs::Query query, ecs::Bus& bus) {
  // 判断编辑模式为移动
  auto& state = query.get_resource<state::State>();

  if (state.getEditingMode() != state::EditingModeType::Affix) {
    return;
  }

  SPDLOG_INFO("----Affix Begin----");
  auto time_start = std::clock();

  // 获取cell和reg
  auto& cell = query.get_resource<qlib::Cell::s_ptr>();
  auto& reg = cell->reg;
  auto& layout_cmd = query.get_resource<layout::LayoutCmd>();

  // 获取输入 坐标系 撤销恢复
  auto& handModule = query.get_resource<vsg::ref_ptr<input::HandleBundle>>();
  auto& axisModule = query.get_resource<axis::Axis>();
  auto& undoRedoModule = query.get_resource<undoRedoT::UndoRedoModule>();

  // 获取移动参数
  auto& move_param = query.get_resource<Param>();
  auto event_writer = query.get_event_writer<Event>();

  auto& copy_param = query.get_resource<copy::Param>();
  auto& shear_param = query.get_resource<shear::Param>();

  auto& draw_pin_param = query.get_resource<qbe::draw::pin::Models>();

  entt::registry* form_reg = nullptr;
  qlib::Cell::s_ptr form_cell = nullptr;
  ecs::Query* form_query = nullptr;
  if (move_param.from_copy) {
    form_reg = copy_param.reg;
    form_cell = copy_param.cell;
    form_query = copy_param.query;
  } else {
    form_reg = shear_param.reg;
    form_cell = shear_param.cell;
    form_query = shear_param.query;
  }

  qbe::utils::remove_invalid_entity<qbe::select::SelectTag>(reg);
  qbe::utils::remove_invalid_entity<copy::CopyTag>(reg);
  qbe::utils::remove_invalid_entity<shear::ShearTag>(reg);
  uint32_t num = utils::valid_entity_num(reg);

  if (form_reg == nullptr || form_cell == nullptr || (num == 0 && form_reg == &reg)) {
    state.exit();

    move_param.reset();
    return;
  }

  stateTransformBegin(move_param, state, handModule, bus);

  // 开始移动逻辑
  if (move_param.state == State::Upatde) {
    // 没有移动对象
    if (move_param.moveing_first) {
      move_param.moveing_first = false;
      move_param.moveing = true;

      auto view_copy = form_reg->view<copy::CopyTag>();
      auto view_shear = form_reg->view<shear::ShearTag>();

      bool first = true;
      qlib::Vec2dArray box = utils::getInitBox();

      // 遍历选中对象
      if (move_param.from_copy) {

        view_copy.each([&form_cell, &form_reg, &layout_cmd, &event_writer, &first, &box](entt::entity entity) {
          add_cache_obj(form_cell, *form_reg, event_writer, layout_cmd, entity, first);
          first = false;

          auto box_t = utils::getBox(*form_reg, entity);
          box = utils::boxAndBox(box_t, box);
        });
      } else {
        view_shear.each([&form_cell, &form_reg, &layout_cmd, &event_writer, &first, &box](entt::entity entity) {
          add_cache_obj(form_cell, *form_reg, event_writer, layout_cmd, entity, first);
          first = false;

          auto box_t = utils::getBox(*form_reg, entity);
          box = utils::boxAndBox(box_t, box);
        });
      }

      qlib::Vec2d center = (box[0] + box[1]) / 2.0;

      // 到格点上
      center.x = int(center.x * 1000) / 1000.0;
      center.y = int(center.y * 1000) / 1000.0;

      // 记录第一次移动的鼠标位置，记录上一次鼠标位置
      qlib::Vec2d pos = {axisModule.real_x, axisModule.real_y};
      move_param.to_center = pos - center;

      update_cache_obj(reg, event_writer, layout_cmd, move_param.to_center, move_param.to_center);

      move_param.first_pos = pos;
      move_param.last_pos = pos;
    } else {
      // 有更新对象，计算距离上一次鼠标的偏移
      qlib::Vec2d now_pos = {axisModule.real_x, axisModule.real_y};
      qlib::Vec2d translate_a = now_pos - move_param.last_pos + move_param.to_center;
      qlib::Vec2d translate_b = now_pos - move_param.first_pos + move_param.to_center;

      update_cache_obj(reg, event_writer, layout_cmd, translate_a, translate_b);

      // 更新鼠标上一次位置
      move_param.last_pos = now_pos;
    }
  }

  // 取消
  if (move_param.state == State::Cancel) {
    delete_cache_obj(reg, event_writer, layout_cmd, query);

    auto& sele_event_writer = query.get_event_writer<select::Event>();
    sele_event_writer.send({select::Code::SelectUpdate});
    sele_event_writer.send({select::Code::HoverUpdate});

    // 移动执行完毕，回退到之前的模式
    state.exit();

    move_param.moveing = false;
    move_param.reset();
  }

  auto current_lib = query.get_resource<qlib::Library::s_ptr>();

  // 完成流程
  if (move_param.state == State::Complete) {
    // 计算鼠标距离第一次移动时的偏移
    qlib::Vec2d now_pos = {axisModule.real_x, axisModule.real_y};
    qlib::Vec2d translate = now_pos - move_param.first_pos + move_param.to_center;

    // 开始undoRedo命令记录
    undoRedoModule.start(cell);

    auto view_sele = reg.view<select::SelectTag>();

    view_sele.each([&reg](entt::entity e) { reg.remove<select::SelectTag>(e); });

    if (form_reg == &reg) {
      auto start = std::chrono::high_resolution_clock::now();

      bool need_open = false;

      // 遍历旧对象
      auto view_old = reg.view<AffixTag>();
      view_old.each([&reg, &undoRedoModule, &translate, &layout_cmd, &move_param, &current_lib, &draw_pin_param, &need_open](entt::entity entity) {
        // 移除操作标记
        reg.remove<AffixTag>(entity);

        if (move_param.from_copy) {
          entt::entity copy_e = entt::null;

          // 拷贝对象
          if (reg.try_get<qlib::Pin::s_ptr>(entity)) {
            auto old_pin = (*reg.try_get<qlib::Pin::s_ptr>(entity));

            auto id = draw_pin_param.getId();
            if (id > 100000) {
              need_open = true;
              return;
            } else {
              draw_pin_param.update(id);
              copy_e = utils::copy(reg, entity, layout_cmd, translate);
              auto new_pin = (*reg.try_get<qlib::Pin::s_ptr>(copy_e));
              new_pin->setId(id);
              new_pin->setName(std::to_string(id));
              layout_cmd.update(copy_e);
            }

          } else {
            copy_e = utils::copy(reg, entity, layout_cmd, translate);
          }

          undoRedoModule.add(copy_e);

          if (reg.try_get<qlib::ViewArea3D::s_ptr>(copy_e) || reg.try_get<qlib::SectionArea3D::s_ptr>(copy_e)) {
            reg.emplace_or_replace<copy::CopyTag>(copy_e);
          }

          reg.emplace_or_replace<select::SelectTag>(copy_e);
        } else {
          // 备份改变前数据
          undoRedoModule.change(entity);

          // 移动旧对象
          utils::translate(reg, entity, translate);

          layout_cmd.update(entity);

          reg.emplace_or_replace<select::SelectTag>(entity);
        }
      });

      if (need_open) {
        QMessageBox::information(nullptr, ("error"), ("编号范围不能超过100000!"));
      }

      auto end = std::chrono::high_resolution_clock::now();

      // 计算持续时间
      auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);

      // 打印执行时间（秒）
      // std::cout << "Paste add time:" << duration.count() << " milliseconds" << std::endl;

      move_param.from_copy = true;
      copy_param.reg = &reg;
      copy_param.cell = cell;
    } else {
      auto current_cell = query.get_resource<qlib::Cell::s_ptr>();

      bool copy_ref = false;

      // 遍历旧对象
      auto view_old = form_reg->view<AffixTag>();
      view_old.each([&form_reg, &reg, &undoRedoModule, &translate, &layout_cmd, &move_param, &current_lib, &current_cell, &copy_ref,
                     &form_query](entt::entity entity) {
        // 移除操作标记
        form_reg->remove<AffixTag>(entity);

        qlib::Reference::s_ptr* ref = (*form_reg).try_get<qlib::Reference::s_ptr>(entity);
        qlib::Cell::s_ptr ref_cell;

        if (ref) {
          ref_cell = (*ref)->cell;

          if ((*ref)->cell == current_cell) {

            auto copy_cell = (*ref)->cell->copy();

            bool first = true;
            bool equal_name = false;
            uint32_t id = 0;

            std::string old_name = copy_cell->name;
            std::string new_name = copy_cell->name;

            while (equal_name || first) {
              first = false;

              for (auto cell : current_lib->cells) {
                if (cell->name == new_name) {
                  equal_name = true;
                  break;
                }
              }

              if (equal_name) {
                id += 1;

                std::string str = " (" + std::to_string(id) + ")";
                new_name = old_name + str;

                equal_name = false;
                first = true;
              } else if (id != 0) {
                copy_cell->name = new_name;
              }
            }

            (*ref)->cell = copy_cell;
          }
          copy_ref = true;
        }

        // 拷贝对象
        entt::entity copy_e = utils::copy(*form_reg, reg, entity, layout_cmd, translate, current_lib);

        if (ref) {
          (*ref)->cell = ref_cell;

          if (ref_cell == current_cell) {
            auto& form_layout_cmd = form_query->get_resource<layout::LayoutCmd>();
            form_layout_cmd.update(entity);
          }
        }

        undoRedoModule.add(copy_e);

        reg.emplace_or_replace<select::SelectTag>(copy_e);
      });

      bus.send<qbe::UiMessage::UpdateFileLisetFromLibrary>(qbe::UiMessage::UpdateFileLisetFromLibrary{current_lib});

      if (copy_ref) {
        layout_cmd.update_cell(current_cell);

        auto& form_layout_cmd = form_query->get_resource<layout::LayoutCmd>();
        form_layout_cmd.update_cell(form_query->get_resource<qlib::Cell::s_ptr>());

        auto& sele_event_writer = form_query->get_event_writer<select::Event>();
        sele_event_writer.send({select::Code::SelectUpdate});
        sele_event_writer.send({select::Code::HoverUpdate});
      }
    }

    // 执行undoRedo，被change的实体将绑定ObjChangeTag
    undoRedoModule.end();

    delete_cache_obj(reg, event_writer, layout_cmd, query);

    auto& sele_event_writer = query.get_event_writer<select::Event>();
    sele_event_writer.send({select::Code::SelectUpdate});
    sele_event_writer.send({select::Code::HoverUpdate});

    // 移动执行完毕，回退到之前的模式
    state.exit();
    auto& move_models = query.get_resource<qbe::move::Param>();
    move_models.pressed_inter_move = false;

    move_param.moveing = false;
    move_param.reset();
  }

  stateTransformEnd(move_param.state);

  auto time_end = std::clock();
  double use_time = static_cast<double>(time_end - time_start);

  SPDLOG_INFO("----Affix end---- use time:{}", use_time);
}

void Plugin::build(ecs::App& app) {
  app.add_stage<InitStage>();
  app.add_stage<UpdateStage>();

  app.init_event<Event>();

  app.add_systems<InitStage>(init);
  app.add_systems<UpdateStage>(update);
  app.add_systems<ecs::stage::Last>(clear_tag);
  app.add_systems<ecs::stage::Last>(clear_events);
}

}  // namespace qbe::affix